package org.dyndns.opendemogroup.optimizer.selections;

import java.util.Random;

import org.dyndns.opendemogroup.optimizer.IOptimizationProblem;
import org.dyndns.opendemogroup.optimizer.ISelection;
import org.dyndns.opendemogroup.optimizer.Member;
import org.dyndns.opendemogroup.optimizer.Pair;
import org.dyndns.opendemogroup.optimizer.Population;

/**
 * Fitness-proportional selection, which is described in slide 9 of
 * <code>howGAsWork1.pdf</code>.
 */
public class RouletteWheel implements ISelection
{

	/**
	 * @see ISelection#select(Random, Population, IOptimizationProblem, int)
	 */
	public Pair<Member, Member> select ( Random randomSource,
			Population population, IOptimizationProblem problem, int loopIndex )
	{
		// { initialization
		Pair<Member, Member> result = new Pair<Member, Member> ( );
		int start, end, direction;

		if ( problem.isMaximizing ( ) )
		{
			start = 0;
			end = population.members.length;
			direction = 1;
		}
		else
		{
			start = population.members.length - 1;
			end = -1;
			direction = -1;
			throw new IllegalStateException (
				"Sorry, I don't know how to program RouletteWheel "
						+ "for minimization problems!" );
		}
		// }

		double r;
		double totalFitness = population.getPopulationFitness ( );
		r = randomSource.nextDouble ( ) * totalFitness;
		int one = rouletteSpin ( population, start, end, direction, r );
		result.first = population.members[one];

		r = randomSource.nextDouble ( ) * totalFitness;
		int two = rouletteSpin ( population, start, end, direction, r );
		result.second = population.members[two];

		return result;
	}

	static int rouletteSpin ( Population population, int start, int end,
			int direction, double r )
	{
		double q = 0.0;
		int retval = end;
		for ( int i = start; i != end; i += direction )
		{
			Member member = population.members[i];
			q += member.getFitness ( );
			if ( q >= r )
			{
				// found it!
				retval = i;
				break;
			}
		}
		return retval;
	}

	public void reset ( Random randomSource, Population population,
			IOptimizationProblem problem )
	{
		// TODO Auto-generated method stub

	}

}
